#include "Streams.h"
#include "hooks.h"


StreamReaderBase::StreamReaderBase( unsigned int caps ) : caps_(caps) {

}

IStream::streamsize_t StreamReaderBase::Size() const {
  // check caps
  BOT_ASSERT(caps_ & IStream::CanTellSize != 0, 
    "Tried to call Size() on a stream that doesn't support CanTellSize");

  return size_;
}

IStream::streamoffs_t StreamReaderBase::CurrentPos() const {
  // check caps
  BOT_ASSERT(caps_ & IStream::CanTellPosition != 0,
    "Tried to call CurrentPos() on a stream that doesn't support CanTellPosition");

  return pos_;
}

bool StreamReaderBase::Seek( IStream::streamoffs_t offset, IStream::SeekType whence ) {
  // check caps
  BOT_ASSERT(caps_ & IStream::CanSeek !=0, 
    "Tried to call Seek() on a stream that doesn't support CanSeek");

  IStream::streampos_t newPos;
  bool ok = true;
  bool canTellSize = !!(caps_ & IStream::CanTellSize);

  switch (whence) {
  case FromBeginning:
    if (offset > size_ ) {
      ok = false;
    } else {
      newPos = offset;
    }
    break;
  case FromEnd:
    BOT_ASSERT (canTellSize,
      "Tried to Seek from end on a stream that doesn't support CanTellSize");

    if (offset > size_) {
      ok = false;
    } else {
      newPos = size_ - offset;
    }
    break;
  case FromCurrent:
    if ((offset > 0 && (offset + pos_) > size_ )
      || (offset < 0 && -offset > pos_)) {
        ok = false;
    } else {
      newPos = CurrentPos() + offset;
    }
    break;
  }

  if (ok) {
    ok = DoSeek(newPos);
  }

  return ok;
}

IStream::streamsize_t StreamReaderBase::Read( IStream::streamsize_t size, char* dest ) {
  bool canTellSize = !!(caps_ & IStream::CanTellSize);
  if (canTellSize 
    && size_ - pos_ > size) {
    size = size_ - pos_;
  }

  BOT_ASSERT(dest != 0);

  return DoRead(size, dest);
}

void StreamReaderBase::ResetStream( IStream::streamsize_t newSize )
{
  pos_ = 0;
  size_ = newSize;
}

